package org.btik.light.mobile.platform.util;

import com.google.gson.Gson;

import okhttp3.*;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.function.Consumer;

/**
 * @author lustre
 * @since 2023/4/29 20:40
 */
public class HttpUtil {
    public static final MediaType JSON_TYPE
            = MediaType.get("application/json; charset=utf-8");

    private static final HttpClientThread httpClientThread;


    private static final Gson gson;

    static {
        httpClientThread = new HttpClientThread();
        httpClientThread.start();
        gson = new Gson();
    }


    public static void doPost(String url, Serializable obj, Consumer<HttpResponse> callBack) {
        RequestBody body = RequestBody.create(gson.toJson(obj), JSON_TYPE);
        Request request = new Request.Builder()
                .url(url)
                .post(body).build();
        httpClientThread.requests.add(new AsyncRequest(request, callBack));
    }

    public static void doGet(String url, Consumer<HttpResponse> callBack) {
        Request request = new Request.Builder()
                .url(url)
                .get().build();
        httpClientThread.requests.add(new AsyncRequest(request, callBack));
    }

    public static <T> T parseJson(String jsonStr, Class<T> tClass) {
        return gson.fromJson(jsonStr, tClass);
    }

    public static <T> List<T> parseListJson(String jsonStr, Class<T[]> tClass) {
        return new ArrayList<>(Arrays.asList(parseArrayJson(jsonStr, tClass)));
    }

    public static <T> T[] parseArrayJson(String jsonStr, Class<T[]> tClass) {
        return gson.fromJson(jsonStr, tClass);
    }

    static class HttpClientThread extends Thread {

        OkHttpClient client = new OkHttpClient();

        LinkedBlockingDeque<AsyncRequest> requests = new LinkedBlockingDeque<>();

        @Override
        public void run() {
            while (!Thread.interrupted()) {
                try {
                    AsyncRequest take = requests.take();
                    Consumer<HttpResponse> callBack = take.callBack;
                    try (Response response = client.newCall(take.request).execute()) {

                        if (callBack != null) {

                            int code = response.code();
                            HttpResponse httpResponse = new HttpResponse(code);
                            httpResponse.success = response.isSuccessful();
                            ResponseBody body = response.body();
                            httpResponse.body = body == null ? null : body.string();
                            httpResponse.header = response.headers().toMultimap();
                            callBack.accept(httpResponse);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        if (callBack != null) {
                            HttpResponse httpResponse = new HttpResponse(-1);
                            httpResponse.success = false;
                            httpResponse.error = e.getMessage();
                            callBack.accept(httpResponse);
                        }
                    }
                } catch (InterruptedException e) {
                    break;
                }

            }

        }
    }

    static class AsyncRequest {
        Request request;
        Consumer<HttpResponse> callBack;

        public AsyncRequest(Request request, Consumer<HttpResponse> callBack) {
            this.request = request;
            this.callBack = callBack;
        }
    }

    public static class HttpResponse {

        boolean success;
        int code;

        Map<String, List<String>> header;

        String body;

        String error;

        public boolean isSuccess() {
            return success;
        }

        public String getError() {
            return error;
        }

        public int getCode() {
            return code;
        }

        public Map<String, List<String>> getHeader() {
            return header;
        }

        public String getBody() {
            return body;
        }

        public HttpResponse(int code) {
            this.code = code;
        }
    }
}
